﻿namespace Basic.Redis.Providers.StackExchange;

/// <summary>
/// Default redis caching provider.
/// </summary>
public partial class DefaultRedisProvider : Basic.Redis.IRedisProvider
{
    public long IncrBy(string cacheKey, long value = 1)
    {
        ArgumentCheck.NotNullOrWhiteSpace(cacheKey, nameof(cacheKey));

        var res = _redisDb.StringIncrement(cacheKey, value);
        return res;
    }

    public async Task<long> IncrByAsync(string cacheKey, long value = 1)
    {
        ArgumentCheck.NotNullOrWhiteSpace(cacheKey, nameof(cacheKey));

        var res = await _redisDb.StringIncrementAsync(cacheKey, value);
        return res;
    }

    public double IncrByFloat(string cacheKey, double value = 1)
    {
        ArgumentCheck.NotNullOrWhiteSpace(cacheKey, nameof(cacheKey));

        var res = _redisDb.StringIncrement(cacheKey, value);
        return res;
    }

    public async Task<double> IncrByFloatAsync(string cacheKey, double value = 1)
    {
        ArgumentCheck.NotNullOrWhiteSpace(cacheKey, nameof(cacheKey));

        var res = await _redisDb.StringIncrementAsync(cacheKey, value);
        return res;
    }

    public bool StringSet(string cacheKey, string cacheValue, TimeSpan? expiration = null, string when = "")
    {
        ArgumentCheck.NotNullOrWhiteSpace(cacheKey, nameof(cacheKey));

        When w = When.Always;

        if (string.Equals(when, "nx", StringComparison.OrdinalIgnoreCase))
            w = When.NotExists;
        else if (string.Equals(when, "xx", StringComparison.OrdinalIgnoreCase))
            w = When.Exists;

        bool flag = _redisDb.StringSet(cacheKey, cacheValue, expiration, w);
        return flag;
    }

    public bool StringSet<T>(string cacheKey, T cacheObj, TimeSpan? expiration = null, string when = "")
    {
        ArgumentCheck.NotNullOrWhiteSpace(cacheKey, nameof(cacheKey));
        When w = When.Always;
        if (string.Equals(when, "nx", StringComparison.OrdinalIgnoreCase))
            w = When.NotExists;
        else if (string.Equals(when, "xx", StringComparison.OrdinalIgnoreCase))
            w = When.Exists;

        RedisValue val = Serializer.Serialize(cacheObj);
        bool flag = _redisDb.StringSet(cacheKey, val, expiration, w);
        return flag;
    }

    public async Task<bool> StringSetAsync(string cacheKey, string cacheValue, TimeSpan? expiration = null, string when = "")
    {
        ArgumentCheck.NotNullOrWhiteSpace(cacheKey, nameof(cacheKey));

        When w = When.Always;
        if (string.Equals(when, "nx", StringComparison.OrdinalIgnoreCase))
            w = When.NotExists;
        else if (string.Equals(when, "xx", StringComparison.OrdinalIgnoreCase))
            w = When.Exists;

        bool flag = await _redisDb.StringSetAsync(cacheKey, cacheValue, expiration, w);
        return flag;
    }

    public async Task<bool> StringSetAsync<T>(string cacheKey, T cacheObj, TimeSpan? expiration = null, string when = "")
    {
        ArgumentCheck.NotNullOrWhiteSpace(cacheKey, nameof(cacheKey));

        When w = When.Always;
        if (string.Equals(when, "nx", StringComparison.OrdinalIgnoreCase))
            w = When.NotExists;
        else if (string.Equals(when, "xx", StringComparison.OrdinalIgnoreCase))
            w = When.Exists;
        RedisValue val = Serializer.Serialize(cacheObj);
        bool flag = await _redisDb.StringSetAsync(cacheKey, val, expiration, w);
        return flag;
    }

    public string StringGet(string cacheKey)
    {
        ArgumentCheck.NotNullOrWhiteSpace(cacheKey, nameof(cacheKey));

        var val = _redisDb.StringGet(cacheKey);
        return val;
    }

    public T StringGet<T>(string cacheKey)
    {
        ArgumentCheck.NotNullOrWhiteSpace(cacheKey, nameof(cacheKey));
        var val = _redisDb.StringGet(cacheKey);
        return Serializer.Deserialize<T>(val);
    }

    public async Task<string> StringGetAsync(string cacheKey)
    {
        ArgumentCheck.NotNullOrWhiteSpace(cacheKey, nameof(cacheKey));
        return (await _redisDb.StringGetAsync(cacheKey)).ToString();
    }

    public async Task<T> StringGetAsync<T>(string cacheKey)
    {
        ArgumentCheck.NotNullOrWhiteSpace(cacheKey, nameof(cacheKey));
        var val = await _redisDb.StringGetAsync(cacheKey);
        if (val.Length() == 0)
            return default(T);

        return Serializer.Deserialize<T>(val);
    }

    public long StringLen(string cacheKey)
    {
        ArgumentCheck.NotNullOrWhiteSpace(cacheKey, nameof(cacheKey));
        return _redisDb.StringLength(cacheKey);
    }

    public async Task<long> StringLenAsync(string cacheKey)
    {
        ArgumentCheck.NotNullOrWhiteSpace(cacheKey, nameof(cacheKey));
        return await _redisDb.StringLengthAsync(cacheKey);
    }

    public long StringSetRange(string cacheKey, long offest, string value)
    {
        ArgumentCheck.NotNullOrWhiteSpace(cacheKey, nameof(cacheKey));
        return (long)(_redisDb.StringSetRange(cacheKey, offest, value));
    }

    public async Task<long> StringSetRangeAsync(string cacheKey, long offest, string value)
    {
        ArgumentCheck.NotNullOrWhiteSpace(cacheKey, nameof(cacheKey));

        var res = await _redisDb.StringSetRangeAsync(cacheKey, offest, value);
        return (long)res;
    }

    public string StringGetRange(string cacheKey, long start, long end)
    {
        ArgumentCheck.NotNullOrWhiteSpace(cacheKey, nameof(cacheKey));

        var res = _redisDb.StringGetRange(cacheKey, start, end);
        return res;
    }

    public async Task<string> StringGetRangeAsync(string cacheKey, long start, long end)
    {
        ArgumentCheck.NotNullOrWhiteSpace(cacheKey, nameof(cacheKey));

        var res = await _redisDb.StringGetRangeAsync(cacheKey, start, end);
        return res;
    }

    public void StringSet(IDictionary<string, string> dict, TimeSpan? expiry = null)
    {
        ArgumentCheck.NotNull(dict, nameof(dict));
        foreach (var kv in dict)
            _redisDb.StringSet(kv.Key, kv.Value, expiry);
    }

    public async Task StringSetAsync(IDictionary<string, string> dict, TimeSpan? expiry = null)
    {
        ArgumentCheck.NotNull(dict, nameof(dict));
        foreach (var kv in dict)
            await _redisDb.StringSetAsync(kv.Key, kv.Value, expiry);
    }

    public void StringSet<T>(IDictionary<string, T> dict, TimeSpan? expiry = null)
    {
        ArgumentCheck.NotNull(dict, nameof(dict));
        foreach (var kv in dict)
            _redisDb.StringSet(kv.Key, Serializer.Serialize(kv.Value), expiry);
    }

    public async Task StringSetAsync<T>(IDictionary<string, T> dict, TimeSpan? expiry = null)
    {
        ArgumentCheck.NotNull(dict, nameof(dict));
        foreach (var kv in dict)
            await _redisDb.StringSetAsync(kv.Key, Serializer.Serialize(kv.Value), expiry);
    }

}